from libc.stdlib cimport rand, RAND_MAX, srand, malloc, free
from cython.operator cimport dereference as deref

ctypedef long long int64_t

cpdef int64_t write_to_buffer(list obj_list, int64_t props_num, list order):
    cdef int64_t size = len(obj_list) * props_num * 8
    cdef void * ptr = malloc(size)
    cdef void * ptr_cp = ptr
    cdef int64_t * ptr_long = <int64_t *>ptr
    cdef double * ptr_double = <double *>ptr
    cdef int64_t int_var
    cdef double double_var
    for i in range(len(obj_list)):
        item = obj_list[i]
        for k in order:
            val = item[k]
            if isinstance(val, int):
                int_var = val
                ptr_long[0] = val
            elif isinstance(val, float):
                double_var = val
                ptr_double[0] = double_var
            else:
                raise NotImplementedError
            ptr_long += 1
            ptr_double += 1
    print((<int64_t*> ptr)[0])
    return <int64_t>ptr

cdef int64_t write_to_buffer_ptr(void *buffer_ptr, list obj_list, int64_t props_num, list order):
    cdef int64_t size = len(obj_list) * props_num * 8
    cdef void * ptr = buffer_ptr
    cdef void * ptr_cp = ptr
    cdef int64_t * ptr_long = <int64_t *>ptr
    cdef double * ptr_double = <double *>ptr
    cdef int64_t int_var
    cdef double double_var
    for i in range(len(obj_list)):
        item = obj_list[i]
        for k in order:
            val = item[k]
            if isinstance(val, int):
                int_var = val
                ptr_long[0] = val
            elif isinstance(val, float):
                double_var = val
                ptr_double[0] = double_var
            else:
                raise NotImplementedError
            ptr_long += 1
            ptr_double += 1
    print((<int64_t*> ptr)[0])
    return <int64_t>ptr

cpdef void from_buffer_ptr(int64_t buffer_ptr, list props, object target_object, bint ignore_object) except *:
    from MelodieAllegro.types import integer, PMBasicType
    from MelodieAllegro.types import double as double_type
    cdef void * ptr
    # 传入的是智能指针的引用，因此先获取智能指针的第2位，也就是指向数据体部分的指针。
    ptr = <void *>((<int64_t *>buffer_ptr)[1])
    cdef str prop_name
    cdef object prop_type
    for prop_name, prop_type, i in props:
        if isinstance(prop_type, PMBasicType):
            if prop_type.to_py_type() == int:
                setattr(target_object, prop_name, (<int64_t *>ptr)[i])
            elif prop_type.to_py_type() == float:
                setattr(target_object, prop_name, (<double *>ptr)[i])
            else:
                raise NotImplementedError(f"prop_type {prop_type} not recognized!")
        else:
            if not ignore_object:
                setattr(target_object, prop_name, (<int64_t *>ptr)[i])
            continue
    return

cdef void init_autoptr(void* auto_pointer_ref, void* body_ref):
    (<int64_t *>auto_pointer_ref)[0] = 1 # 引用计数为1
    (<void **>auto_pointer_ref)[1] = body_ref # body
    (<int64_t *>auto_pointer_ref)[2] = 0 # 强引用


cpdef int64_t alloc_obj_memory(list obj_list, int64_t props_num, list order):
    from MelodieAllegro.types import PMObjectType
    cdef int64_t auto_pointer_size = PMObjectType.AUTO_POINTER_SIZE * 8
    cdef int64_t body_size = len(obj_list) * props_num * 8
    cdef void * auto_pointer_ref = malloc(auto_pointer_size)
    cdef void * body_ref = malloc(body_size)
    init_autoptr(auto_pointer_ref, body_ref)
    write_to_buffer_ptr(body_ref, obj_list, props_num, order)

    return <int64_t>auto_pointer_ref

cdef void init_array_autoptr(void* auto_pointer_ref, void* body_ref, int64_t length):
    (<int64_t *>auto_pointer_ref)[0] = 1 # 引用计数为1
    (<void **>auto_pointer_ref)[1] = body_ref # data
    (<int64_t *>auto_pointer_ref)[2] = 0 # 强引用
    (<int64_t *>auto_pointer_ref)[3] = length


cpdef void incref(int64_t auto_ptr_ref):
    (<int64_t *>auto_ptr_ref)[0] += 1 # 引用计数为1

cpdef void decref(int64_t auto_ptr_ref):
    (<int64_t *>auto_ptr_ref)[0] -= 1 # 引用计数为1

cpdef int64_t getref(int64_t auto_ptr_ref):
    return (<int64_t *>auto_ptr_ref)[0] # 引用计数为1

cpdef list int_array_to_list(int64_t auto_ptr_arr):
    """
    将整数或指针类型的列表，转换为一个int为元素的list
    """
    cdef int64_t* data = (<int64_t **>auto_ptr_arr)[1]
    cdef int64_t length = (<int64_t *>auto_ptr_arr)[3]
    cdef list ret = []
    cdef int i
    for i in range(length):
        ret.append(data[i])
    return ret

cpdef int64_t alloc_array_memory(list values):
    from MelodieAllegro.types import PMObjectType
    cdef int64_t auto_pointer_size = PMObjectType.AUTO_POINTER_SIZE * 8
    cdef int64_t body_size = len(values) * 8
    cdef void * auto_pointer_ref = malloc(auto_pointer_size)
    cdef void * body_ref = malloc(body_size)
    cdef int64_t val = 0
    init_array_autoptr(auto_pointer_ref, body_ref, len(values))
    for i, val in enumerate(values):
        (<int64_t *>body_ref)[i] = val
    return <int64_t>auto_pointer_ref

